﻿using System;
using ABMath.ModelFramework.Data;
using ABMath.ModelFramework.Models;
using MathNet.Numerics;
using MathNet.Numerics.Distributions;
using NUnit.Framework;

namespace ABMath.Tests.ModelFramework.Models
{
    [TestFixture]
    public class ARMAXModelTest
    {
        private ARMAXModel model1;

        private TimeSeries testTS;
        private TimeSeries auxTS;

        private StandardDistribution normalSim;

        [SetUp]
        public void SetUp()
        {
            model1 = new ARMAXModel(1, 1, 1);
            model1.SetARPolynomial(new Polynomial(new[] { 1.0, -0.5 }));
            model1.SetMAPolynomial(new Polynomial(new[] { 1.0, -0.4 }));
            model1.SetGamma(0, 0.5);

            testTS = new TimeSeries();
            auxTS = new TimeSeries();

            normalSim = new StandardDistribution();
            var current = new DateTime(2001, 1, 1);
            for (int t=0 ; t<100 ; ++t)
            {
                double s1 = normalSim.NextDouble();
                double s2 = normalSim.NextDouble();

                testTS.Add(current, s1, false);
                auxTS.Add(current, s2, false);

                current = new DateTime(current.AddDays(1).Ticks);
            }
        }

        [Test]
        public void RealTimeTest()
        {

            // get predictors using standard non-real-time approach
            model1.SetInput(0, testTS, null);
            model1.SetInput(1, auxTS, null);
            model1.LogLikelihood(null, 0.0, true);

            var preds = model1.GetOutput(3) as TimeSeries;
            var predName = model1.GetOutputName(3);
            Assert.AreEqual(predName, StandardOutputs.OneStepPredictor);

            // get predictors using real-time interface
            model1.ResetRealTimePrediction();
            var realTimePredictors = new TimeSeries();
            for (int t=0 ; t<testTS.Count ; ++t)
            {
                double mn = model1.GetCurrentPredictor(testTS.TimeStamp(t)).Mean;
                realTimePredictors.Add(testTS.TimeStamp(t), mn, false);

                model1.Register(testTS.TimeStamp(t), testTS[t], new[] {auxTS[t]});
            }

            // now compare the results
            for (int t = 0; t < testTS.Count; ++t )
            {
                double err = preds[t] - realTimePredictors[t];
                Assert.LessOrEqual(Math.Abs(err), 0.00001);
            }
        }
    }
}
